import { login, logout, refreshToken, getAuthInfo } from '@/api/user'
import { Commit, Dispatch } from 'vuex'
import { storage, token } from '@/util'
import { LoginRequest, Menu, Permission, User } from '@/types'

export interface AuthInfo {
    user?: User
    menus?: Menu[],
    permissions?: Permission[],
}
const CACHE_AUTH: string = '__auth_info'

const auth: AuthInfo = storage.get(CACHE_AUTH, {});

export interface IUserState {
    user?: User
    menus?: Menu[],
    permissions?: Permission[],
    refreshAt: number;
}

interface Ctx {
    commit: Commit,
    dispatch: Dispatch,
    state: IUserState
}

const state = () => ({
    user: auth.user,
    menus: auth.menus,
    permissions: auth.permissions,
    refreshAt: 0
})

const mutations = {
    setUser(state: IUserState, user?: User) {
        state.user = user;
    },
    setMenus(state: IUserState, menus: Menu[]) {
        state.menus = menus
    },
    setPermissions(state: IUserState, permissions: Permission[]) {
        state.permissions = permissions
    },
    setRefreshAt(state: IUserState, refreshAt: number) {
        state.refreshAt = refreshAt
    },
}

const actions = {
    async login({ commit, dispatch }: Ctx, loginRequest: LoginRequest) {
        const response = await login(loginRequest);
        if (response != undefined && response.status == 200) {
            token.set(response.data.token)
            return true;
        }
        dispatch('destorySession')
        return false;
    },
    async refresh({ commit, dispatch, state }: Ctx) {
        const now = (new Date()).getTime();
        if (now - state.refreshAt < 5000) {
            return true;
        }
        const response = await refreshToken()
        if (response != undefined && response.status == 200) {
            token.set(response.data.token, response.data.expired_at);
            commit('setRefreshAt', now)
            return true;
        }

        dispatch('destorySession');
        return false;
    },

    async authInfo({ commit, dispatch, state }: Ctx) {
        const response = await getAuthInfo()
        if (response != undefined && response.status == 200) {
            commit('setUser', response.data.user)
            commit('setMenus', response.data.menus)
            commit('setPermissions', response.data.permissions)
            storage.set(CACHE_AUTH, response.data)
        }
        return response;
    },

    async logout({ commit, dispatch }: Ctx) {
        const response = await logout();
        if (response != undefined && response.status == 200) {
            dispatch('destorySession');
            return true;
        }
        return false;
    },

    destorySession({ commit, dispatch }: Ctx) {
        token.remove()
        storage.remove(CACHE_AUTH)
        commit('setUser', undefined)
        commit('setMenus', [])
        commit('setPermissions', [])
    }
}

export default { namespaced: true, state, mutations, actions }
